msg_tool\scripts\favorite/
disasm.rs

1use crate::ext::io::*;
2use crate::types::*;
3use crate::utils::encoding::*;
4use anyhow::Result;
5use serde::{Deserialize, Serialize};
6use std::io::{Read, Seek, SeekFrom};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9enum Oper {
10    // Byte
11    B,
12    // Word
13    W,
14    // Double Word
15    D,
16    // String
17    S,
18    // Float
19    F,
20}
21
22use Oper::*;
23
24#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
25#[serde(tag = "t", content = "c")]
26pub enum Operand {
27    B(u8),
28    W(u16),
29    D(u32),
30    S(String),
31    F(f32),
32}
33
34impl Operand {
35    pub fn len(&self, encoding: Encoding) -> Result<usize> {
36        Ok(match self {
37            Operand::B(_) => 1,
38            Operand::W(_) => 2,
39            Operand::D(_) => 4,
40            Operand::S(s) => {
41                let bytes = encode_string(encoding, s, true)?;
42                // null terminator + length byte
43                bytes.len() + 2
44            }
45            Operand::F(_) => 4,
46        })
47    }
48}
49
50const OPS: [(u8, &[Oper]); 49] = [
51    (0x00, &[]),     //noop
52    (0x01, &[B, B]), //initstack
53    (0x02, &[D]),    //call
54    (0x03, &[W]),    //syscall
55    (0x04, &[]),     //ret
56    (0x05, &[]),     //ret2
57    (0x06, &[D]),    //jmp
58    (0x07, &[D]),    //jmpcond
59    (0x08, &[]),     //pushtrue
60    (0x09, &[]),     //pushfalse
61    (0x0a, &[D]),    //pushint
62    (0x0b, &[W]),    //pushint
63    (0x0c, &[B]),    //pushint
64    (0x0d, &[F]),    //pushfloat * unused
65    (0x0e, &[S]),    //pushstring
66    (0x0f, &[W]),    //pushglobal
67    (0x10, &[B]),    //pushstack
68    (0x11, &[W]),    //unknown
69    (0x12, &[B]),    //unknown
70    (0x13, &[]),     //pushtop
71    (0x14, &[]),     //pushtmp
72    (0x15, &[W]),    //popglobal
73    (0x16, &[B]),    //copystack
74    (0x17, &[W]),    //unknown
75    (0x18, &[B]),    //unknown
76    (0x19, &[]),     //neg
77    (0x1a, &[]),     //add
78    (0x1b, &[]),     //sub
79    (0x1c, &[]),     //mul
80    (0x1d, &[]),     //div
81    (0x1e, &[]),     //mod
82    (0x1f, &[]),     //test
83    (0x20, &[]),     //logand
84    (0x21, &[]),     //logor
85    (0x22, &[]),     //eq
86    (0x23, &[]),     //neq
87    (0x24, &[]),     //gt
88    (0x25, &[]),     //le
89    (0x26, &[]),     //lt
90    (0x27, &[]),     //ge
91    (0x33, &[]),
92    (0x3f, &[]),
93    (0x40, &[]),
94    (0xb3, &[]),
95    (0xb8, &[]),
96    (0xd8, &[]),
97    (0xf0, &[]),
98    (0x52, &[]),
99    (0x9e, &[]),
100];
101
102#[derive(Debug, Clone, Serialize, Deserialize)]
103pub struct Func {
104    pub pos: u64,
105    pub opcode: u8,
106    pub operands: Vec<Operand>,
107}
108
109#[derive(Debug, Clone, Serialize, Deserialize)]
110pub struct Data {
111    pub functions: Vec<Func>,
112    pub main_script: Vec<Func>,
113    pub extra_data: Vec<u8>,
114}
115
116impl Data {
117    pub fn disasm<R: Read + Seek>(mut reader: R, encoding: Encoding) -> Result<Self> {
118        let mut data = Data {
119            functions: Vec::new(),
120            main_script: Vec::new(),
121            extra_data: Vec::new(),
122        };
123        let script_len = reader.read_u32()? as u64;
124        let main_script_data = reader.peek_u32_at(script_len)? as u64;
125        {
126            let mut target = &mut data.functions;
127            let mut pos = reader.stream_position()?;
128            while pos < script_len {
129                if pos >= main_script_data {
130                    target = &mut data.main_script;
131                }
132                target.push(Self::read_func(&mut reader, encoding)?);
133                pos = reader.stream_position()?;
134            }
135        }
136        reader.seek(SeekFrom::Start(script_len + 4))?;
137        reader.read_to_end(&mut data.extra_data)?;
138        Ok(data)
139    }
140
141    fn read_func<R: Read + Seek>(reader: &mut R, encoding: Encoding) -> Result<Func> {
142        let pos = reader.stream_position()?;
143        let opcode = reader.read_u8()?;
144        let operands = if let Some((_, ops)) = OPS.iter().find(|(code, _)| *code == opcode) {
145            let mut operands = Vec::with_capacity(ops.len());
146            for &op in *ops {
147                let operand = match op {
148                    B => Operand::B(reader.read_u8()?),
149                    W => Operand::W(reader.read_u16()?),
150                    D => Operand::D(reader.read_u32()?),
151                    S => {
152                        let len = reader.read_u8()? as usize;
153                        let s = reader.read_cstring()?;
154                        if s.as_bytes_with_nul().len() != len {
155                            return Err(anyhow::anyhow!(
156                                "String length mismatch at {:#x}: expected {}, got {}",
157                                pos,
158                                len,
159                                s.as_bytes_with_nul().len()
160                            ));
161                        }
162                        let s = decode_to_string(encoding, s.as_bytes(), true)?;
163                        Operand::S(s)
164                    }
165                    F => Operand::F(reader.read_f32()?),
166                };
167                operands.push(operand);
168            }
169            operands
170        } else {
171            return Err(anyhow::anyhow!(
172                "Unknown opcode: {:#x} at {:#x}",
173                opcode,
174                pos
175            ));
176        };
177        Ok(Func {
178            pos,
179            opcode,
180            operands,
181        })
182    }
183}